﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using TheStar.MODEL;
using TheStar.Lib;

namespace MODEL
{
    public class Vizinhanca
    {
        #region fields
        private readonly Hashtable table;
        private readonly Hashtable valuedTable;
        private int currentIndex;
        private double[,] adjMatrix;
        #endregion

        #region constructors
        public Vizinhanca()
        {
            this.adjMatrix = new double[0, 0];
            this.table = new Hashtable();
            this.valuedTable = new Hashtable();
            this.currentIndex = 0;
        }
        #endregion

        #region properties
        public IEnumerable<Cidade> Cidades
        {
            get { return this.table.Keys.Cast<Cidade>().ToArray(); }
        }
        #endregion

        #region methods
        public void Add(Cidade cidade)
        {
            this.AddAndRecalculate(cidade);
        }
        public void Add(Cidade origem, Cidade destino, double custo)
        {
            this.AddAndRecalculate(origem, destino);

            int origemIndex = (int)this.table[origem];
            int destinoIndex = (int)this.table[destino];

            this.adjMatrix[origemIndex, destinoIndex] = custo;
            this.adjMatrix[destinoIndex, origemIndex] = custo;
        }
        private bool AddAndRecalculate(params Cidade[] cidades)
        {
            int count = 0;
            foreach (Cidade item in cidades)
            {
                if (!this.table.ContainsKey(item))
                {
                    this.table.Add(item, this.currentIndex);
                    this.valuedTable.Add(this.currentIndex++, item);
                    count++;
                }
            }
            if (count > 0)
            {
                double[,] oldMatrix = this.adjMatrix;
                int size = (int)Math.Sqrt((double)oldMatrix.Length);
                int newLength = size + count;
                this.adjMatrix = new double[newLength, newLength];
                
                for (int i = 0; i < size; i++)
                for (int j = 0; j < size; j++)
                {
                    this.adjMatrix[i, j] = oldMatrix[i, j];
                }
                return true;
            }
            else
            {
                return false;
            }
        }
        public IEnumerable<Transition> GetTransitions(Cidade raiz)
        {
            if (raiz == null)
            {
                throw new ArgumentNullException("raiz");
            }
            object ret = this.table[raiz];
            if (ret == null)
            {
                throw new ArgumentException("A cidade passada como parametro não está cadastrada");
            }
            int index = (int)ret;

            int size = (int)Math.Sqrt((double)this.adjMatrix.Length);
            List<Transition> transitions = new List<Transition>();
            
            for (int j = 0; j < size; j++)
            {
                if (this.adjMatrix[index, j] > 0)
                {
                    transitions.Add(new Transition(this.valuedTable[j], this.adjMatrix[index, j]));
                }
            }
            return transitions;
        }
        #endregion
    }
}
